package com.yizhubao.app.utils.net;



import com.franmontiel.persistentcookiejar.ClearableCookieJar;
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
import com.yizhubao.app.app.YZBApp;
import com.yizhubao.app.utils.Constants;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

import h.framework.pacy.P;
import h.framework.pacy.utils.LogUtil;
import h.framework.pacy.utils.PreferencesUtil;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * @author PACY
 * 创建时间 19/1/9 14:36.
 * 邮箱 pengwwe457621023@qq.com
 * 类描述 RetrofitUtil
 */
public class RetrofitUtil {


    private static final int TIME_OUT = 10;//超时时间
    private static ApiService mApiService;

    private static ApiService getApiService;


    public static ApiService getApiService() {
        if (mApiService == null) {
            ClearableCookieJar cookieJar =
                    new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(P.getContext()));
            OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
            //设置请求超时时长
            okHttpClientBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
            //启用Log日志
            if(YZBApp.getInstance().isDebug){
                okHttpClientBuilder.addInterceptor(getHttpLoggingInterceptor());
            }
            okHttpClientBuilder.addInterceptor(chain -> {
                Request original = chain.request();
                Request request;
                //如果token不为空则添加token到参数列表
                request = original.newBuilder()
                        .addHeader("Content-Type", "application/json")
                        .addHeader("source","android")
                        .addHeader("Cookie", "JSESSIONID="+PreferencesUtil.get(Constants.COOKIE, ""))
//                        .addHeader("Cookie", "JSESSIONID=SHSHSHSHSHSHS")
                        .method(original.method(), original.body())
                        .build();
//                    }
                return chain.proceed(request);
            });

            Retrofit retrofit = new Retrofit.Builder()
                    //服务器地址
                    .baseUrl(Constants.BASE_URL)
                    //配置转化库，采用Gson
                    .addConverterFactory(GsonConverterFactory.create())
                    //配置回调库，采用RxJava
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    //设置OKHttpClient为网络客户端
                    .client(okHttpClientBuilder.build()).build();

            mApiService = retrofit.create(ApiService.class);
        }
        return mApiService;
    }


    public static ApiService getMApiService() {
        if (getApiService == null) {
            OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
            //设置请求超时时长
            okHttpClientBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
            //启用Log日志
            if(YZBApp.getInstance().isDebug){
                okHttpClientBuilder.addInterceptor(getHttpLoggingInterceptor());
            }
            okHttpClientBuilder.addInterceptor(chain -> {
                Request original = chain.request();
                Request request;
                //如果token不为空则添加token到参数列表
                request = original.newBuilder()
                        .addHeader("Content-Type", "application/json")
                        .addHeader("source","android")
                        .addHeader("Cookie", "JSESSIONID="+PreferencesUtil.get(Constants.COOKIE, ""))
                        .method(original.method(), original.body())
                        .build();
//                    }
                return chain.proceed(request);
            });

            Retrofit retrofit = new Retrofit.Builder()
                    //服务器地址
                    .baseUrl("https://respect-static.oss-cn-beijing.aliyuncs.com/")
                    //配置转化库，采用Gson
                    .addConverterFactory(GsonConverterFactory.create())
                    //配置回调库，采用RxJava
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    //设置OKHttpClient为网络客户端
                    .client(okHttpClientBuilder.build()).build();

            getApiService = retrofit.create(ApiService.class);
        }
        return getApiService;
    }



    //提供Log日志插值器
    public static HttpLoggingInterceptor getHttpLoggingInterceptor() {
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                try {
                    String text = URLDecoder.decode(message, "utf-8");
                    LogUtil.i(text);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    LogUtil.i(message);
                }
            }
        });
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        return loggingInterceptor;
    }


    /**
     * 对observable进行统一转换（用于非文件下载请求）
     *
     * @param observable       被订阅者
     * @param observer         订阅者
     * @param lifecycleSubject 生命周期事件发射者
     */
    public static void composeToSubscribe(Observable observable, Observer observer, PublishSubject<LifeCycleEvent> lifecycleSubject) {
        //默认在进入DESTROY状态时发射一个事件来终止网络请求
        composeToSubscribe(observable, observer, LifeCycleEvent.DESTROY, lifecycleSubject);
    }

    /**
     * 对observable进行统一转换（用于非文件下载请求）
     *
     * @param observable       被订阅者
     * @param observer         订阅者
     * @param event            生命周期中的某一个状态，比如传入DESTROY，则表示在进入destroy状态时lifecycleSubject会发射一个事件从而终止请求
     * @param lifecycleSubject 生命周期事件发射者
     */
    public static void composeToSubscribe(Observable observable, Observer observer, LifeCycleEvent event, PublishSubject<LifeCycleEvent> lifecycleSubject) {
        observable.compose(getTransformer(event, lifecycleSubject)).subscribe(observer);
    }


    /**
     * 获取统一转换用的Transformer（用于非文件下载请求）
     *
     * @param event            生命周期中的某一个状态，比如传入DESTROY，则表示在进入destroy状态时
     *                         lifecycleSubject会发射一个事件从而终止请求
     * @param lifecycleSubject 生命周期事件发射者
     */
    public static <T> ObservableTransformer<T, T> getTransformer(final LifeCycleEvent event, final PublishSubject<LifeCycleEvent> lifecycleSubject) {
        return new ObservableTransformer() {
            @Override
            public ObservableSource apply(Observable upstream) {

                //当lifecycleObservable发射事件时，终止操作。
                //统一在请求时切入io线程，回调后进入ui线程
                //加入失败重试机制（延迟3秒开始重试，重试3次）
                return upstream
                        .takeUntil(getLifeCycleObservable(event, lifecycleSubject))
                        .retryWhen(new RetryFunction(2, 3))
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }


    //获取用于控制声明周期的Observable
    public static Observable<LifeCycleEvent> getLifeCycleObservable(final LifeCycleEvent event, PublishSubject<LifeCycleEvent> lifecycleSubject) {
        return lifecycleSubject.filter(new Predicate<LifeCycleEvent>() {
            @Override
            public boolean test(LifeCycleEvent lifeCycleEvent) throws Exception {
                //当生命周期为event状态时，发射事件
                return lifeCycleEvent.equals(event);
            }
        }).take(1);
    }


    //请求失败重试机制
    public static class RetryFunction implements Function<Observable<Throwable>, ObservableSource<?>> {

        private int retryDelaySeconds;//延迟重试的时间
        private int retryCount;//记录当前重试次数
        private int retryCountMax;//最大重试次数

        public RetryFunction(int retryDelaySeconds, int retryCountMax) {
            this.retryDelaySeconds = retryDelaySeconds;
            this.retryCountMax = retryCountMax;
        }

        @Override
        public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
            //方案一：使用zip控制重试次数，重试3次后不再重试（会隐式回调onComplete结束请求，但我需要的是回调onError，所以没采用方案一）
//            return Observable.zip(throwableObservable,Observable.range(1, retryCountMax),new BiFunction<Throwable, Integer, Throwable>() {
//                @Override
//                public Throwable apply(Throwable throwable, Integer integer) throws Exception {
//                    LogUtil.e("ljy",""+integer);
//                    return throwable;
//                }
//            }).flatMap(new Function<Throwable, ObservableSource<?>>() {
//                @Override
//                public ObservableSource<?> apply(Throwable throwable) throws Exception {
//                    if (throwable instanceof UnknownHostException) {
//                        return Observable.error(throwable);
//                    }
//                    return Observable.timer(retryDelaySeconds, TimeUnit.SECONDS);
//                }
//            });


            //方案二：使用全局变量来控制重试次数，重试3次后不再重试，通过代码显式回调onError结束请求
            return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(Throwable throwable) throws Exception {
                    //如果失败的原因是UnknownHostException（DNS解析失败，当前无网络），则没必要重试，直接回调error结束请求即可
                    if (throwable instanceof UnknownHostException) {
                        return Observable.error(throwable);
                    }

                    //没超过最大重试次数的话则进行重试
                    if (++retryCount <= retryCountMax) {
                        //延迟retryDelaySeconds后开始重试
                        return Observable.timer(retryDelaySeconds, TimeUnit.SECONDS);
                    }

                    return Observable.error(throwable);
                }
            });
        }
    }

//    /**
//     * 请求拦截器，修改请求header
//     */
//    public class RequestInterceptor implements Interceptor{
//        @Override
//        public Response intercept(Chain chain) throws IOException {
//            Request request = chain.request()
//                .newBuilder()
//                .addHeader("Content-Type", "text/html; charset=UTF-8")
////                    .addHeader("Accept-Encoding", "*")
//                .addHeader("Connection", "keep-alive")
//                .addHeader("Accept", "*/*")
//                .addHeader("Access-Control-Allow-Origin", "*")
//                .addHeader("Access-Control-Allow-Headers", "X-Requested-With")
//                .addHeader("Vary", "Accept-Encoding")
////                    .addHeader("Cookie", "add cookies here")
//                .build();
//            return chain.proceed(request);
//        }
//    }

}
